using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Runtime.InteropServices;
using PickGold.Charting;

namespace PickGold.Charting.ChartTypes
{
	internal class KagiChart : StepLineChart
	{
		internal int currentKagiDirection;
		internal Color kagiUpColor = Color.Empty;

		protected override GraphicsPath Draw3DSurface(ChartArea area, ChartGraphics graph, Matrix3D matrix, LightStyle lightStyle, DataPoint3D prevDataPointEx, float positionZ, float depth, ArrayList points, int pointIndex, int pointLoopIndex, float tension, DrawingOperationTypes operationType, float topDarkening, float bottomDarkening, PointF thirdPointPosition, PointF fourthPointPosition, bool clippedSegment)
		{
			GraphicsPath path = ((operationType & DrawingOperationTypes.CalcElementPath) == DrawingOperationTypes.CalcElementPath) ? new GraphicsPath() : null;
			if (base.centerPointIndex == 0x7fffffff)
			{
				base.centerPointIndex = base.GetCenterPointIndex(points);
			}
			DataPoint3D pointd = (DataPoint3D)points[pointIndex];
			int neighborPointIndex = pointIndex;
			DataPoint3D pointd2 = ChartGraphics.FindPointByIndex(points, pointd.index - 1, base.multiSeries ? pointd : null, ref neighborPointIndex);
			DataPoint3D pointd3 = pointd;
			if (prevDataPointEx.dataPoint.IsEmpty)
			{
				pointd3 = prevDataPointEx;
			}
			else if (pointd2.index > pointd.index)
			{
				pointd3 = pointd2;
			}
			Color gray = base.useBorderColor ? pointd3.dataPoint.BorderColor : pointd3.dataPoint.Color;
			ChartDashStyle borderDashStyle = pointd3.dataPoint.BorderDashStyle;
			if (pointd3.dataPoint.IsEmpty && (pointd3.dataPoint.Color == Color.Empty))
			{
				gray = Color.Gray;
			}
			if (pointd3.dataPoint.IsEmpty && (pointd3.dataPoint.BorderDashStyle == ChartDashStyle.NotSet))
			{
				borderDashStyle = ChartDashStyle.Solid;
			}
			if (this.currentKagiDirection == 0)
			{
				this.kagiUpColor = pointd.dataPoint.series.Color;
				string text = pointd.dataPoint.series["PriceUpColor"];
				ColorConverter converter = new ColorConverter();
				if (text != null)
				{
					try
					{
						this.kagiUpColor = (Color)converter.ConvertFromString(null, CultureInfo.InvariantCulture, text);
					}
					catch
					{
						throw new InvalidOperationException(SR.ExceptionKagiAttributeFormatInvalid("Up Brick color"));
					}
				}
				this.currentKagiDirection = (pointd2.yPosition > pointd.yPosition) ? 1 : -1;
			}
			Color backColor = (this.currentKagiDirection == 1) ? this.kagiUpColor : gray;
			DataPoint3D pointd4 = new DataPoint3D();
			pointd4.xPosition = pointd.xPosition;
			pointd4.yPosition = pointd2.yPosition;
			bool flag = true;
			if ((pointIndex + 1) < points.Count)
			{
				DataPoint3D pointd5 = (DataPoint3D)points[pointIndex + 1];
				if (pointd5.index == pointd2.index)
				{
					flag = false;
				}
			}
			if ((base.centerPointIndex != 0x7fffffff) && (pointIndex >= base.centerPointIndex))
			{
				flag = false;
			}
			DataPoint3D secondPoint = null;
			if (pointd.index >= 3)
			{
				int num2 = (pointd2.yPosition > pointd.yPosition) ? 1 : -1;
				if (num2 != this.currentKagiDirection)
				{
					DataPoint3D pointd7 = ChartGraphics.FindPointByIndex(points, pointd.index - 2, base.multiSeries ? pointd : null, ref neighborPointIndex);
					bool flag2 = false;
					if (((pointd2.yPosition > pointd7.yPosition) && (pointd2.yPosition > pointd.yPosition)) && (pointd7.yPosition > pointd.yPosition))
					{
						flag2 = true;
					}
					else if (((pointd2.yPosition < pointd7.yPosition) && (pointd2.yPosition < pointd.yPosition)) && (pointd7.yPosition < pointd.yPosition))
					{
						flag2 = true;
					}
					if (flag2)
					{
						secondPoint = new DataPoint3D();
						secondPoint.xPosition = pointd.xPosition;
						secondPoint.yPosition = pointd7.yPosition;
						secondPoint.dataPoint = pointd.dataPoint;
					}
				}
			}
			GraphicsPath[] pathArray = new GraphicsPath[3];
			for (int i = 0; i < 2; i++)
			{
				DataPoint3D firstPoint = pointd2;
				DataPoint3D pointd9 = pointd;
				LineSegmentType first = LineSegmentType.First;
				switch (i)
				{
					case 0:
						first = flag ? LineSegmentType.First : LineSegmentType.Last;
						pointd4.dataPoint = flag ? pointd.dataPoint : pointd2.dataPoint;
						firstPoint = flag ? pointd2 : pointd4;
						pointd9 = flag ? pointd4 : pointd;
						break;

					case 1:
						first = !flag ? LineSegmentType.First : LineSegmentType.Last;
						pointd4.dataPoint = !flag ? pointd.dataPoint : pointd.dataPoint;
						firstPoint = !flag ? pointd2 : pointd4;
						pointd9 = !flag ? pointd4 : pointd;
						break;
				}
				if ((first == LineSegmentType.First) || (secondPoint == null))
				{
					pathArray[i] = new GraphicsPath();
					pathArray[i] = graph.Draw3DSurface(area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, backColor, pointd3.dataPoint.BorderColor, pointd3.dataPoint.BorderWidth, borderDashStyle, firstPoint, pointd9, points, pointIndex, 0f, operationType, first, base.showPointLines, false, area.ReverseSeriesOrder, base.multiSeries, 0, true);
				}
				else
				{
					if (!flag)
					{
						backColor = (this.currentKagiDirection == -1) ? this.kagiUpColor : gray;
					}
					pathArray[i] = new GraphicsPath();
					pathArray[i] = graph.Draw3DSurface(area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, backColor, pointd3.dataPoint.BorderColor, pointd3.dataPoint.BorderWidth, borderDashStyle, firstPoint, secondPoint, points, pointIndex, 0f, operationType, LineSegmentType.Middle, base.showPointLines, false, area.ReverseSeriesOrder, base.multiSeries, 0, true);
					graph.frontLinePen = null;
					this.currentKagiDirection = (this.currentKagiDirection == 1) ? -1 : 1;
					if (flag)
					{
						backColor = (this.currentKagiDirection == 1) ? this.kagiUpColor : gray;
					}
					else
					{
						backColor = (this.currentKagiDirection == -1) ? this.kagiUpColor : gray;
					}
					pathArray[2] = new GraphicsPath();
					pathArray[2] = graph.Draw3DSurface(area, matrix, lightStyle, SurfaceNames.Top, positionZ, depth, backColor, pointd3.dataPoint.BorderColor, pointd3.dataPoint.BorderWidth, borderDashStyle, secondPoint, pointd9, points, pointIndex, 0f, operationType, first, base.showPointLines, false, area.ReverseSeriesOrder, base.multiSeries, 0, true);
					if (!flag)
					{
						backColor = (this.currentKagiDirection == 1) ? this.kagiUpColor : gray;
					}
				}
				graph.frontLinePen = null;
			}
			if (path != null)
			{
				if (pathArray[0] != null)
				{
					path.AddPath(pathArray[0], true);
				}
				if (pathArray[1] != null)
				{
					path.AddPath(pathArray[1], true);
				}
				if (pathArray[2] != null)
				{
					path.AddPath(pathArray[2], true);
				}
			}
			return path;
		}

		protected override void DrawLine(ChartGraphics graph, CommonElements common, DataPoint point, Series series, PointF[] points, int pointIndex, float tension)
		{
			if (pointIndex > 0)
			{
				if (this.currentKagiDirection == 0)
				{
					this.kagiUpColor = ChartGraphics.GetGradientColor(series.Color, Color.Black, 0.5);
					string text = series["PriceUpColor"];
					ColorConverter converter = new ColorConverter();
					if (text != null)
					{
						try
						{
							this.kagiUpColor = (Color)converter.ConvertFromString(null, CultureInfo.InvariantCulture, text);
						}
						catch
						{
							throw new InvalidOperationException(SR.ExceptionKagiAttributeFormatInvalid("Up Brick color"));
						}
					}
					this.currentKagiDirection = (points[pointIndex - 1].Y > points[pointIndex].Y) ? 1 : -1;
				}
				Color color = (this.currentKagiDirection == 1) ? this.kagiUpColor : point.Color;
				PointF tf = points[pointIndex - 1];
				PointF tf2 = new PointF(points[pointIndex].X, points[pointIndex - 1].Y);
				PointF tf3 = points[pointIndex];
				PointF empty = PointF.Empty;
				if (pointIndex >= 2)
				{
					int num = (points[pointIndex - 1].Y > points[pointIndex].Y) ? 1 : -1;
					if (num != this.currentKagiDirection)
					{
						PointF tf5 = points[pointIndex - 2];
						bool flag = false;
						if (((tf.Y > tf5.Y) && (tf.Y > tf3.Y)) && (tf5.Y > tf3.Y))
						{
							flag = true;
						}
						else if (((tf.Y < tf5.Y) && (tf.Y < tf3.Y)) && (tf5.Y < tf3.Y))
						{
							flag = true;
						}
						if (flag)
						{
							empty.Y = tf5.Y;
							empty.X = tf2.X;
						}
					}
				}
				tf.X = (float)Math.Round((double)tf.X);
				tf.Y = (float)Math.Round((double)tf.Y);
				tf2.X = (float)Math.Round((double)tf2.X);
				tf2.Y = (float)Math.Round((double)tf2.Y);
				tf3.X = (float)Math.Round((double)tf3.X);
				tf3.Y = (float)Math.Round((double)tf3.Y);
				if (!empty.IsEmpty)
				{
					empty.X = (float)Math.Round((double)empty.X);
					empty.Y = (float)Math.Round((double)empty.Y);
				}
				graph.DrawLineRel(color, point.BorderWidth, point.BorderDashStyle, graph.GetRelativePoint(tf), graph.GetRelativePoint(tf2), series.ShadowColor, series.ShadowOffset);
				if (empty.IsEmpty)
				{
					graph.DrawLineRel(color, point.BorderWidth, point.BorderDashStyle, graph.GetRelativePoint(tf2), graph.GetRelativePoint(tf3), series.ShadowColor, series.ShadowOffset);
				}
				else
				{
					graph.DrawLineRel(color, point.BorderWidth, point.BorderDashStyle, graph.GetRelativePoint(tf2), graph.GetRelativePoint(empty), series.ShadowColor, series.ShadowOffset);
					this.currentKagiDirection = (this.currentKagiDirection == 1) ? -1 : 1;
					color = (this.currentKagiDirection == 1) ? this.kagiUpColor : point.Color;
					graph.DrawLineRel(color, point.BorderWidth, point.BorderDashStyle, graph.GetRelativePoint(empty), graph.GetRelativePoint(tf3), series.ShadowColor, series.ShadowOffset);
				}
				if (common.ProcessModeRegions)
				{
					using (GraphicsPath path = new GraphicsPath())
					{
						try
						{
							path.AddLine(tf, tf2);
							path.AddLine(tf2, tf3);
							path.Widen(new Pen(point.Color, (float)(point.BorderWidth + 2)));
						}
						catch (OutOfMemoryException)
						{
						}
						catch (ArgumentException)
						{
						}
						PointF relativePoint = PointF.Empty;
						float[] coord = new float[path.PointCount * 2];
						PointF[] pathPoints = path.PathPoints;
						for (int i = 0; i < path.PointCount; i++)
						{
							relativePoint = graph.GetRelativePoint(pathPoints[i]);
							coord[2 * i] = relativePoint.X;
							coord[(2 * i) + 1] = relativePoint.Y;
						}
						common.HotRegionsList.AddHotRegion(path, false, coord, point, series.Name, pointIndex);
					}
				}
			}
		}

		private static void FillKagiData(Series series, Series originalData)
		{
			int index = 0;
			if (series.IsCustomPropertySet("UsedYValue"))
			{
				int num2;
				if (!int.TryParse(series["UsedYValue"], NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
				{
					throw new InvalidOperationException(SR.ExceptionKagiAttributeFormatInvalid("UsedYValue"));
				}
				index = num2;
				if (index >= series.YValuesPerPoint)
				{
					throw new InvalidOperationException(SR.ExceptionKagiAttributeOutOfRange("UsedYValue"));
				}
			}
			double percentOfPrice = 0.0;
			double reversalAmount = GetReversalAmount(series, out percentOfPrice);
			double naN = double.NaN;
			int num6 = 0;
			int num7 = 0;
			foreach (DataPoint point in originalData.Points)
			{
				if (double.IsNaN(naN))
				{
					naN = point.YValues[index];
					DataPoint item = point.Clone();
					item["OriginalPointIndex"] = num7.ToString(CultureInfo.InvariantCulture);
					item.series = series;
					item.XValue = point.XValue;
					item.YValues[0] = point.YValues[index];
					item.Tag = point;
					series.Points.Add(item);
					num7++;
					continue;
				}
				if (percentOfPrice != 0.0)
				{
					reversalAmount = (naN / 100.0) * percentOfPrice;
				}
				int num8 = 0;
				if (point.YValues[index] > naN)
				{
					num8 = 1;
				}
				else if (point.YValues[index] < naN)
				{
					num8 = -1;
				}
				else
				{
					num8 = 0;
				}
				if (num8 != 0)
				{
					if (num8 == num6)
					{
						series.Points[series.Points.Count - 1].YValues[0] = point.YValues[index];
						series.Points[series.Points.Count - 1]["OriginalPointIndex"] = num7.ToString(CultureInfo.InvariantCulture);
						series.Points[series.Points.Count - 1].Tag = point;
					}
					else
					{
						if (Math.Abs((double)(point.YValues[index] - naN)) < reversalAmount)
						{
							num7++;
							continue;
						}
						DataPoint point3 = point.Clone();
						point3["OriginalPointIndex"] = num7.ToString(CultureInfo.InvariantCulture);
						point3.series = series;
						point3.XValue = point.XValue;
						point3.YValues[0] = point.YValues[index];
						point3.Tag = point;
						series.Points.Add(point3);
					}
					naN = point.YValues[index];
					num6 = num8;
				}
				num7++;
			}
		}

		public override Image GetImage(ChartTypeRegistry registry)
		{
			return (Image)registry.ResourceManager.GetObject(this.Name + "ChartType");
		}

		protected override PointF[] GetPointsPosition(ChartGraphics graph, Series series, bool indexedSeries)
		{
			PointF[] tfArray = new PointF[series.Points.Count];
			int pointIndex = 0;
			foreach (DataPoint point in series.Points)
			{
				double axisValue = this.GetYValue(base.Common, base.Area, series, point, pointIndex, base.YValueIndex);
				double position = base.VAxis.GetPosition(axisValue);
				double num4 = base.HAxis.GetPosition(point.XValue);
				if (indexedSeries)
				{
					num4 = base.HAxis.GetPosition((double)(pointIndex + 1));
				}
				tfArray[pointIndex] = new PointF((float)((num4 * (graph.Common.ChartPicture.Width - 1)) / 100.0), (float)((position * (graph.Common.ChartPicture.Height - 1)) / 100.0));
				pointIndex++;
			}
			return tfArray;
		}

		private static double GetReversalAmount(Series series, out double percentOfPrice)
		{
			double num = 1.0;
			percentOfPrice = 3.0;
			if (series.IsCustomPropertySet("ReversalAmount"))
			{
				double num3;
				string s = series["ReversalAmount"].Trim();
				bool flag = s.EndsWith("%", StringComparison.Ordinal);
				if (flag)
				{
					s = s.Substring(0, s.Length - 1);
				}
				if (flag)
				{
					double num2;
					if (!double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
					{
						throw new InvalidOperationException(SR.ExceptionKagiAttributeFormatInvalid("ReversalAmount"));
					}
					percentOfPrice = num2;
					return num;
				}
				if (!double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out num3))
				{
					throw new InvalidOperationException(SR.ExceptionKagiAttributeFormatInvalid("ReversalAmount"));
				}
				num = num3;
				percentOfPrice = 0.0;
			}
			return num;
		}

		public override void Paint(ChartGraphics graph, CommonElements common, ChartArea area, Series seriesToDraw)
		{
			this.currentKagiDirection = 0;
			base.Paint(graph, common, area, seriesToDraw);
		}

		internal static void PrepareData(Series series)
		{
			if ((string.Compare(series.ChartTypeName, "Kagi", StringComparison.OrdinalIgnoreCase) == 0) && series.IsVisible())
			{
				Chart chart = series.Chart;
				if (chart == null)
				{
					throw new InvalidOperationException(SR.ExceptionKagiNullReference);
				}
				ChartArea area = chart.ChartAreas[series.ChartArea];
				foreach (Series series2 in chart.Series)
				{
					if ((series2.IsVisible() && (series2 != series)) && (area == chart.ChartAreas[series2.ChartArea]))
					{
						throw new InvalidOperationException(SR.ExceptionKagiCanNotCombine);
					}
				}
				string name = "KAGI_ORIGINAL_DATA_" + series.Name;
				if (chart.Series.IndexOf(name) == -1)
				{
					Series item = new Series(name, series.YValuesPerPoint);
					item.Enabled = false;
					item.IsVisibleInLegend = false;
					chart.Series.Add(item);
					foreach (DataPoint point in series.Points)
					{
						item.Points.Add(point);
					}
					series.Points.Clear();
					if (series.IsCustomPropertySet("TempDesignData"))
					{
						item["TempDesignData"] = "true";
					}
					series["OldXValueIndexed"] = series.IsXValueIndexed.ToString(CultureInfo.InvariantCulture);
					series["OldYValuesPerPoint"] = series.YValuesPerPoint.ToString(CultureInfo.InvariantCulture);
					series.IsXValueIndexed = true;
					if ((series.ChartArea.Length > 0) && series.IsXValueDateTime())
					{
						Axis axis = area.GetAxis(AxisName.X, series.XAxisType, series.XSubAxisName);
						if ((axis.Interval == 0.0) && (axis.IntervalType == DateTimeIntervalType.Auto))
						{
							bool flag = false;
							double maxValue = double.MaxValue;
							double minValue = double.MinValue;
							foreach (DataPoint point2 in item.Points)
							{
								if (!point2.IsEmpty)
								{
									if (point2.XValue != 0.0)
									{
										flag = true;
									}
									if (point2.XValue > minValue)
									{
										minValue = point2.XValue;
									}
									if (point2.XValue < maxValue)
									{
										maxValue = point2.XValue;
									}
								}
							}
							if (flag)
							{
								series["OldAutomaticXAxisInterval"] = "true";
								DateTimeIntervalType auto = DateTimeIntervalType.Auto;
								axis.interval = axis.CalcInterval(maxValue, minValue, true, out auto, series.XValueType);
								axis.intervalType = auto;
							}
						}
					}
					FillKagiData(series, item);
				}
			}
		}

		internal static bool UnPrepareData(Series series)
		{
			bool flag;
			int num;
			if (!series.Name.StartsWith("KAGI_ORIGINAL_DATA_", StringComparison.Ordinal))
			{
				return false;
			}
			Chart chart = series.Chart;
			if (chart == null)
			{
				throw new InvalidOperationException(SR.ExceptionKagiNullReference);
			}
			Series fromSeries = chart.Series[series.Name.Substring(0x13)];
			Series.MovePositionMarkers(fromSeries, series);
			fromSeries.Points.Clear();
			if (!series.IsCustomPropertySet("TempDesignData"))
			{
				foreach (DataPoint point in series.Points)
				{
					fromSeries.Points.Add(point);
				}
			}
			bool flag2 = bool.TryParse(fromSeries["OldXValueIndexed"], out flag);
			fromSeries.IsXValueIndexed = flag2 && flag;
			if (int.TryParse(fromSeries["OldYValuesPerPoint"], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				fromSeries.YValuesPerPoint = num;
			}
			fromSeries.DeleteCustomProperty("OldXValueIndexed");
			fromSeries.DeleteCustomProperty("OldYValuesPerPoint");
			series["OldAutomaticXAxisInterval"] = "true";
			if (fromSeries.IsCustomPropertySet("OldAutomaticXAxisInterval"))
			{
				fromSeries.DeleteCustomProperty("OldAutomaticXAxisInterval");
				if (fromSeries.ChartArea.Length > 0)
				{
					Axis axis = chart.ChartAreas[fromSeries.ChartArea].GetAxis(AxisName.X, fromSeries.XAxisType, fromSeries.XSubAxisName);
					axis.interval = 0.0;
					axis.intervalType = DateTimeIntervalType.Auto;
				}
			}
			chart.Series.Remove(series);
			return true;
		}

		public override string Name
		{
			get
			{
				return "Kagi";
			}
		}
	}
}

